package com.acwer.drgs.performance.word;

import com.acwer.dao.domain.CHSDRG;
import com.acwer.dao.domain.DrgStd;
import com.acwer.dao.mapper.CHSDRGMapper;
import com.acwer.dao.mapper.DrgStdMapper;
import com.acwer.drgs.performance.controller.PfmController;
import com.acwer.drgs.performance.domain.EncodingUtil;
import com.acwer.drgs.performance.es.domain.MiniPerformanceInfo;
import com.acwer.drgs.performance.es.domain.PerfmDic;
import com.acwer.drgs.performance.es.repo.PerfmDicRepo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.deepoove.poi.data.ChartMultiSeriesRenderData;
import com.deepoove.poi.data.ChartSingleSeriesRenderData;
import com.deepoove.poi.data.Charts;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.*;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeValuesSourceBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.ParsedComposite;
import org.elasticsearch.search.aggregations.bucket.composite.TermsValuesSourceBuilder;
import org.elasticsearch.search.aggregations.bucket.filter.ParsedFilter;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.aggregations.metrics.ParsedCardinality;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.aggregations.metrics.ParsedValueCount;
import org.elasticsearch.search.aggregations.pipeline.BucketSortPipelineAggregationBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class DefaultSummaryWord extends GenerWord {

    public DefaultSummaryWord() {
        super("conf/performance.docx");
    }

    protected String downname(String cpy) {
        return cpy+"-绩效报告";
    }


    public  class UIMethodInvoke{
        public String f2(Double d){
            return String.format("%.2f",d).toString();
        }
        public String f0(Double d){
            return String.format("%.0f",d).toString();
        }

        public String ykmax(JSONArray array,String scol,String tcol,int skip,int take,Double totalDocCount){
            array.sort(new Comparator<Object>() {
                @Override
                public int compare(Object o1, Object o2) {
                    JSONObject oo1=(JSONObject)o1;
                    JSONObject oo2=(JSONObject)o2;
                    Double d1=Double.parseDouble(oo1.getString(scol));
                    Double d2=Double.parseDouble(oo2.getString(scol));
                    if(scol.equals("weightSum")){
                        return d2.compareTo(d1);
                    }
                    return d1.compareTo(d2);
                }
            });

            List<Object> objects=array;
            if(array.size()-1>take){
                objects = array.subList(skip, take);
            }

            List<String> ls = objects.stream().map(it -> ((JSONObject) it).getString(tcol)).collect(Collectors.toList());
            String join = String.join("、", ls);
            double docCount = objects.stream().mapToDouble(it -> ((JSONObject) it).getDouble("docCount")).sum();
            double totalyk = objects.stream().mapToDouble(it -> ((JSONObject) it).getDouble("yk")).sum();

            join+="，共计"+f0(docCount)+"例病案，"+"占入组数的"+f2((docCount*100/totalDocCount))+"%，共计";
            if(totalyk>0){
                join+="盈利";
            }else join+="亏损";
            totalyk=Math.abs(totalyk);
            join+=f2(totalyk/10000)+"万元";
            return join;
        }
        public String max(JSONArray array,String scol,String tcol,int skip,int take){
            array.sort(new Comparator<Object>() {
                @Override
                public int compare(Object o1, Object o2) {
                    JSONObject oo1=(JSONObject)o1;
                    JSONObject oo2=(JSONObject)o2;

                    return oo2.getDouble(scol).compareTo(oo1.getDouble(scol));
                }
            });
            List<Object> objects=array;
            if(array.size()-1>take){
                objects = array.subList(skip, take);
            }

            List<String> ls = objects.stream().map(it -> ((JSONObject) it).getString(tcol)).collect(Collectors.toList());

            return String.join("、",ls);
        }

        public String cmiDesc(Double d){
            JSONArray cmiRange = dic("CMIRange");
            if(cmiRange==null) return "正常";
            for (Object o : cmiRange) {
                JSONObject oo=(JSONObject)o;
                Double gt=oo.getDouble("gt");
                Double lt=oo.getDouble("lt");

                if(gt<=d&&lt>=d) return oo.getString("name");
            }
            return "";
        }

        public String adrgls(JSONArray array,Long total){
            List<String> ls=new ArrayList<>();
            for (int i = 0; i < array.size(); i++) {
               JSONObject o=(JSONObject) array.get(i);
                String adrgName = o.getString("adrgName");
                if(StringUtils.isEmpty(adrgName)) continue;

                Long docCount=o.getLong("docCount");
                if(i==0){
                    ls.add(adrgName+"占比最高，达到了"+f2((docCount*100.0/total))+"%");
                }else if(i==1){
                    ls.add("其次是"+adrgName+"，占比"+f2((docCount*100.0/total))+"%");
                }else {
                    ls.add(adrgName+"，占比"+f2((docCount*100.0/total))+"%");
                }
            }
            return String.join("；",ls);
        }

    }


    @Autowired
    DrgStdMapper drgStdMapper;

    @Autowired
    PerfmDicRepo dicRepo;

    public JSONArray dic(String name){
        NativeSearchQueryBuilder nQuery = new NativeSearchQueryBuilder();
        nQuery.withPageable(PageRequest.of(0,1));
        nQuery.withQuery(QueryBuilders.termQuery("code.keyword",name));
        Page<PerfmDic> search = dicRepo.search(nQuery.build());
        if(search.getSize()==0) return null;
        String val = search.getContent().get(0).getVal();
        return JSON.parseArray(val);
    }

    private List<PfmController.SimpleEsWhere> getBaseWhere(Map<String,Object> inps){
        List<PfmController.SimpleEsWhere> wheres=new ArrayList<PfmController.SimpleEsWhere>();
        if(inps.containsKey("cpy")&&!StringUtils.isEmpty(inps.get("cpy").toString())){
            wheres.add(new PfmController.SimpleEsWhere("username.keyword","eq",inps.get("cpy").toString()));
        }
        return wheres;
    }

    protected Map<String, Object> generParams(Map<String,Object> inps) throws ParseException {

        Map<String, Object> params=new HashMap<>();
        //---------格式化开始日期、结束日期
        SimpleDateFormat informat=new SimpleDateFormat("yyyyMMdd");
        SimpleDateFormat outformat=new SimpleDateFormat("yyyy年MM月");
        Date stimeDate = informat.parse(inps.get("stime").toString());
        Date etimeDate = informat.parse(inps.get("etime").toString());

        String stimefrm = outformat.format(stimeDate);
        String etimefrm = outformat.format(etimeDate);
        params.put("stime",stimefrm);
        params.put("etime",etimefrm);
        String time=inps.get("time").toString();
        List<PfmController.SimpleEsWhere> baseWhere = getBaseWhere(inps);
        //获取文档数和入组人数
        JSONArray array = innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "", JSON.toJSONString(baseWhere),null, 0, 1).getJSONArray("ls");
        int totalDocCount=0;

        if(array.size()>0){
            totalDocCount=((JSONObject)(array.get(0))).getInteger("docCount");
//            ingrpCount=((JSONObject)(array.get(0))).getInteger("ingrpCount");
            params.put("totalDocCount",totalDocCount);
//            params.put("ingrpCount",ingrpCount);
        }


        //获取医保病人
        List<PfmController.SimpleEsWhere> wheres=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
            }
        };
        wheres.addAll(baseWhere);

        int ingrpCount=0;
        array = innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "", JSON.toJSONString(wheres), null,0, 1).getJSONArray("ls");
        if(array.size()>0){
            int ybbr=((JSONObject)(array.get(0))).getInteger("docCount");
            ingrpCount=((JSONObject)(array.get(0))).getInteger("ingrpCount");
            params.put("ingrpCount",ingrpCount);
            params.put("ybbr",ybbr);
        }

        UIMethodInvoke ui = new UIMethodInvoke();
        //-------未入组原因列表------
        List<PfmController.SimpleEsWhere> notIngrpwheres=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
                add(new PfmController.SimpleEsWhere("ingrp","eq",false));
            }
        };
        notIngrpwheres.addAll(baseWhere);

        JSONArray notIngrpLs=innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "grpinfo.rzlb", JSON.toJSONString(notIngrpwheres), null,0, 1000).getJSONArray("ls");
        JSONArray rzlbs=new JSONArray();
        for (Object o : notIngrpLs) {
            JSONObject oo = (JSONObject) o;
            String k = oo.getString("grpinforzlb");
            Long docCount = oo.getLong("docCount");
            String val1 = ui.f2(docCount * 100.0 / ingrpCount);
            JSONObject no = new JSONObject();
            no.put("key", k);
            no.put("val", docCount);
            no.put("val1", val1);
            rzlbs.add(no);
        }
        if(rzlbs.size()>0){
            params.put("rzlbs",rzlbs);
        }



        //二、医院DRG总体情况
        //1.医疗服务量
        List<PfmController.SimpleEsWhere> wheres2=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ingrp","eq",true));
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
            }
        };
        wheres2.addAll(baseWhere);

        JSONObject summaryTotal = innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "grpinfo.mdc", JSON.toJSONString(wheres2), null,0, 100);
        JSONObject totalObj=summaryTotal.getJSONObject("total");
        params.put("mdcTotal",totalObj);
        array=summaryTotal.getJSONArray("ls");
        List<DrgStd> drgStds = drgStdMapper.selectList(null);
        Map<String,String>mdcMap=new HashMap<>();
        drgStds.forEach(it->{
            if(!StringUtils.isEmpty(it.getMdc专业())){
                mdcMap.put(it.getMdc专业(),it.getMdc中文名称());
            }

        });
        List<String>useMdcs=array.stream().map(it->((JSONObject)it).getString("grpinfomdc")).distinct().collect(Collectors.toList());
        array.forEach(it->{
            JSONObject o=(JSONObject)it;
            String mdc = o.getString("grpinfomdc");
            if(mdcMap.containsKey(mdc)){
                o.put("mdcName",mdcMap.get(mdc));
            }

        });
        //未使用的MDC
        List<String> notUsedMdc = mdcMap.keySet().stream().filter(it -> !useMdcs.contains(it)).collect(Collectors.toList());
        if(notUsedMdc.size()>0){
            List<String> notUsedMdcNames = notUsedMdc.stream().map(it -> mdcMap.get(it)).collect(Collectors.toList());
            params.put("notUsedMdc",String.join("、",notUsedMdcNames));
            params.put("usedMdcCount",mdcMap.size()-notUsedMdcNames.size());
        }else {
            //使用了的MDC数量
            params.put("usedMdcCount",mdcMap.size());
        }
        params.put("mdcLs",array);
        //生成MDC图标
        params.put("mdcChart",mdcChar(array));

        //2.医院技术结构

        JSONArray nkAndWkAndCZ = innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "grpinfo.drgingrptype", JSON.toJSONString(wheres2),null, 0, 100).getJSONArray("ls");
       params.put("drgPieChart",drgPieChart(nkAndWkAndCZ,params));

       //3.医院病种结构
        List<CHSDRG> chsdrgs = chsdrgMapper.selectList(null);

        for (String s : "nk,wk,cz".split(",")) {

            List<PfmController.SimpleEsWhere> nkwhere=new ArrayList<PfmController.SimpleEsWhere>(){
                {
                    add(new PfmController.SimpleEsWhere("ingrp","eq",true));
                    add(new PfmController.SimpleEsWhere("grpinfo.drgingrptype.keyword","eq",s));
                    add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
                }
            };
            nkwhere.addAll(baseWhere);

                JSONObject nkObj= innerGrpls(time, inps.get("stime").toString(),
                        inps.get("etime").toString(), "grpinfo.adrg", JSON.toJSONString(nkwhere),"pCount-desc", 0, 10);
                JSONArray nkArray=nkObj.getJSONArray("ls");

                nkArray.forEach(it->{
                    JSONObject o=(JSONObject)it;
                    String k = o.getString("grpinfoadrg");
                    List<String> adrgNames = chsdrgs.stream().filter(it2 -> it2.get编码().equalsIgnoreCase(k)).map(it2 -> it2.get名称()).collect(Collectors.toList());
                    if(adrgNames.size()>0){
                        o.put("adrgName",adrgNames.get(0));
                    }
                });

                if(nkArray.size()>0){
                    params.put(s+"AdrgTotal",nkObj.get("total"));
                    params.put(s+"AdrgPieChart",adrgPipeChar(nkArray,s,((JSONObject)nkObj.get("total")).getLong("pCount")));
                    params.put(s+"AdrgLs",nkArray);
                }else{
                    JSONObject nullTotalObj=new JSONObject();
                    nullTotalObj.put("adrgName","");
                    nullTotalObj.put("docCount",0);
                    nullTotalObj.put("pCount",0);
                    JSONArray array1 = new JSONArray(Arrays.asList(nullTotalObj));
                    params.put(s+"AdrgTotal",nullTotalObj);
                    params.put(s+"AdrgLs",array1);
                    params.put(s+"AdrgPieChart",adrgPipeChar(array1,s,0L));
                }

        }

        //三、医院及各科室绩效评价情况
        summaryTotal = innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "cybf,grpinfo.drg,grpinfo.name", JSON.toJSONString(wheres2), null,0, 10000);

        params.put("ksLs",bf(summaryTotal));

        //第三部分 基于 DRG 支付下的运营风险分析

        //极低费用统计
        List<PfmController.SimpleEsWhere> lowCostWhere=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ingrp","eq",true));
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
                add(new PfmController.SimpleEsWhere("grpinfo.costratio","lte",0.3));
            }
        };
        lowCostWhere.addAll(baseWhere);

        JSONObject lowCostObj=innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "", JSON.toJSONString(lowCostWhere), null,0, 1).getJSONObject("total");
        params.put("lowCost",lowCostObj);

        //极高费用统计
        List<PfmController.SimpleEsWhere> heightCostWhere=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ingrp","eq",true));
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
                add(new PfmController.SimpleEsWhere("grpinfo.costratio","gte",3));
            }
        };
        heightCostWhere.addAll(baseWhere);

        JSONObject heightCostObj=innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "cybf", JSON.toJSONString(heightCostWhere), "_count-desc",0, 1000);

        JSONObject heightCostTotal = heightCostObj.getJSONObject("total");
        heightCostObj.getJSONArray("ls").forEach(it->{
            JSONObject o=(JSONObject)it;
            o.put("pCount",ui.f0(o.getDouble("pCount")));
            o.put("r",ui.f2(o.getDouble("pCount")*100/heightCostTotal.getDouble("pCount")));

        });
        params.put("heightCostLs",heightCostObj.get("ls"));
        params.put("heightCost",heightCostTotal);

        //正常倍率0.3-3
        List<PfmController.SimpleEsWhere> normalCostWhere=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ingrp","eq",true));
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
                add(new PfmController.SimpleEsWhere("grpinfo.costratio","gt",0.3));
                add(new PfmController.SimpleEsWhere("grpinfo.costratio","lt",3));
            }
        };
        normalCostWhere.addAll(baseWhere);

        JSONObject normalCostObj=innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "", JSON.toJSONString(normalCostWhere), "_count-desc",0, 1);
        params.put("normalCost",normalCostObj.getJSONObject("total"));
        //正常倍率1-2
        List<PfmController.SimpleEsWhere> normalCostWhere2=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ingrp","eq",true));
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
                add(new PfmController.SimpleEsWhere("grpinfo.costratio","gt",1));
                add(new PfmController.SimpleEsWhere("grpinfo.costratio","lte",2));
            }
        };
        normalCostWhere2.addAll(baseWhere);

        JSONObject normalCostObj2=innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "cybf", JSON.toJSONString(normalCostWhere2), "_count-desc",0, 10000);
        params.put("normalCost2",normalCostObj2.getJSONObject("total"));
        JSONArray normalCost2ls=normalCostObj2.getJSONArray("ls");
        normalCost2ls.forEach(it->{
            JSONObject o=(JSONObject)it;
            o.put("pCount",ui.f0(o.getDouble("pCount")));
            o.put("zfySum",ui.f2(o.getDouble("zfySum")));
            o.put("benchmarkFeeSum",ui.f2(o.getDouble("benchmarkFeeSum")));
            o.put("yk",ui.f2(o.getDouble("benchmarkFeeSum")-o.getDouble("zfySum")));
            o.put("r",ui.f2((o.getDouble("benchmarkFeeSum")-o.getDouble("zfySum"))*100/o.getDouble("zfySum")));
        });
        params.put("normalCost2ls",normalCost2ls);

        //正常倍率2-3
        List<PfmController.SimpleEsWhere> normalCostWhere3=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ingrp","eq",true));
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
                add(new PfmController.SimpleEsWhere("grpinfo.costratio","gt",2));
                add(new PfmController.SimpleEsWhere("grpinfo.costratio","lte",3));
            }
        };
        normalCostWhere3.addAll(baseWhere);

        JSONObject normalCostObj3=innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "cybf", JSON.toJSONString(normalCostWhere3), "_count-desc",0, 10000);
        params.put("normalCost3",normalCostObj3.getJSONObject("total"));
        JSONArray normalCost3ls=normalCostObj3.getJSONArray("ls");
        normalCost3ls.forEach(it->{
            JSONObject o=(JSONObject)it;
            o.put("pCount",ui.f0(o.getDouble("pCount")));
            o.put("zfySum",ui.f2(o.getDouble("zfySum")));
            o.put("benchmarkFeeSum",ui.f2(o.getDouble("benchmarkFeeSum")));
            o.put("yk",ui.f2(o.getDouble("benchmarkFeeSum")-o.getDouble("zfySum")));
            o.put("r",ui.f2((o.getDouble("benchmarkFeeSum")-o.getDouble("zfySum"))*100/o.getDouble("zfySum")));
        });
        params.put("normalCost3ls",normalCost3ls);

        //六、各DRG组亏损分析
        //表11
        List<PfmController.SimpleEsWhere> drgAllWhere=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ingrp","eq",true));
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
            }
        };
        drgAllWhere.addAll(baseWhere);
        JSONObject drgAllObj=innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "grpinfo.drg,grpinfo.name", JSON.toJSONString(drgAllWhere), "_count-desc",0, 10000);
        params.put("drgAllTotal",drgAllObj.getJSONObject("total"));
        JSONArray drgAllLs=drgAllObj.getJSONArray("ls");
        drgAllLs.forEach(it->{
            JSONObject o=(JSONObject)it;
            o.put("pCount",ui.f0(o.getDouble("pCount")));
            o.put("zfySum",ui.f2(o.getDouble("zfySum")));
            o.put("weightSum",ui.f2(o.getDouble("weightSum")));
            o.put("benchmarkFeeSum",ui.f2(o.getDouble("benchmarkFeeSum")));
            o.put("yk",o.getDouble("benchmarkFeeSum")-o.getDouble("zfySum"));
            o.put("lj",ui.f2((o.getDouble("benchmarkFeeAvg")-o.getDouble("zfyAvg"))));
        });
        drgAllLs.sort(new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                JSONObject oo2=(JSONObject)o2;
                JSONObject oo1=(JSONObject)o1;
                return oo2.getDouble("yk").compareTo(oo1.getDouble("yk"));
            }
        });
        drgAllLs.forEach(it->{
            JSONObject o=(JSONObject)it;
            o.put("yk",ui.f2(o.getDouble("yk")));

        });
        params.put("drgAllLs",drgAllLs);
        params.put("drgAllLs20",drgAllLs.subList(0,Math.min(20,drgAllLs.size())));

        //表12   收入减少的TOP20 医生组
        List<PfmController.SimpleEsWhere> zyysWhere=new ArrayList<PfmController.SimpleEsWhere>(){
            {
                add(new PfmController.SimpleEsWhere("ingrp","eq",true));
                add(new PfmController.SimpleEsWhere("ylfkfs.keyword","in","01,02"));
            }
        };
        zyysWhere.addAll(baseWhere);

        JSONObject zyysAllObj=innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "zyys", JSON.toJSONString(zyysWhere), "_count-desc",0, 10000);
        params.put("zyysAllTotal",drgAllObj.getJSONObject("total"));
        JSONArray zyysAllLs=zyysAllObj.getJSONArray("ls");
        zyysAllLs.forEach(it->{
            JSONObject o=(JSONObject)it;
            o.put("pCount",ui.f0(o.getDouble("pCount")));
            o.put("zfySum",ui.f2(o.getDouble("zfySum")));
            o.put("benchmarkFeeSum",ui.f2(o.getDouble("benchmarkFeeSum")));
            o.put("yk",o.getDouble("benchmarkFeeSum")-o.getDouble("zfySum"));
            o.put("lj",ui.f2((o.getDouble("benchmarkFeeAvg")-o.getDouble("zfyAvg"))));
        });
        zyysAllLs.sort(new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                JSONObject oo2=(JSONObject)o2;
                JSONObject oo1=(JSONObject)o1;
                return oo1.getDouble("yk").compareTo(oo2.getDouble("yk"));
            }
        });
        zyysAllLs.forEach(it->{
            JSONObject o=(JSONObject)it;
            o.put("yk",ui.f2(o.getDouble("yk")));

        });
        params.put("zyysAllLs",zyysAllLs);
        params.put("zyysAllLs20",zyysAllLs.subList(0,Math.min(20,zyysAllLs.size())));
        params.put("ui",ui);

        //RW>=2
        List<Object> cmigt2Ls = drgAllLs.stream().filter(it -> {
            JSONObject o = (JSONObject) it;
            return o.getDouble("weightAvg") >= 2;
        }).collect(Collectors.toList());

        cmigt2Ls.sort(new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                JSONObject oo1=(JSONObject)o1;
                JSONObject oo2=(JSONObject)o2;
                Double d1=Double.parseDouble(oo1.getString("weightSum"));
                Double d2=Double.parseDouble(oo2.getString("weightSum"));
                return d2.compareTo(d1);
            }
        });
        params.put("cmigt2ls20",cmigt2Ls.subList(0,Math.min(20,cmigt2Ls.size())));
        params.put("cmigt2ls",cmigt2Ls);
        params.put("cmi2docCount",cmigt2Ls.stream().mapToLong(it->((JSONObject)it).getLong("docCount")).sum());

        //极高费用DRG支付标准：DRG组前5%按实际费用支付+剩下的按支付标准支付

        JSONObject hJsonArray=innerGrpls(time, inps.get("stime").toString(),
                inps.get("etime").toString(), "grpinfo.drg", JSON.toJSONString(heightCostWhere), "zfySum-desc",0, 1000);

        JSONArray hList=hJsonArray.getJSONArray("ls");
//        List<Object> hList = hJsonArray.stream().filter(it -> ((JSONObject) it).getDouble("weightAvg") >= 3).collect(Collectors.toList());
//        hList.sort(new Comparator<Object>() {
//            @Override
//            public int compare(Object o1, Object o2) {
//                JSONObject oo1=(JSONObject)o1;
//                JSONObject oo2=(JSONObject)o2;
//                Double d1=Double.parseDouble(oo1.getString("zfySum"));
//                Double d2=Double.parseDouble(oo2.getString("zfySum"));
//                return d2.compareTo(d1);
//            }
//        });
        long top5 = Math.round(heightCostTotal.getDouble("pCount") * 0.05);
        Double hSum=0d;
        for (int i = 0; i < hList.size(); i++) {
            JSONObject o=(JSONObject)hList.get(i);
            if(top5!=0&&top5<=i){
                hSum+=o.getDouble("zfySum");
            }else {
                hSum+=o.getDouble("benchmarkFeeSum");
            }
        }
        params.put("hPaySum",hSum);
        params.put("curDate",outformat.format(new Date()));
        return params;
    }


    //医院及各科室绩效评价情况
    public JSONArray bf(JSONObject o){
        JSONArray ls=o.getJSONArray("ls");
        JSONObject total=o.getJSONObject("total");
        Long totalDocCount=total.getLong("pCount");
        JSONArray rs=new JSONArray();

        Map<String,JSONArray> lsMap=new HashMap<String,JSONArray>();
        for (Object l : ls) {
            JSONObject oo=(JSONObject)l;
            String cybf=oo.getString("cybf");
            if(!lsMap.containsKey(cybf)){
                lsMap.put(cybf,new JSONArray());
            }
            JSONArray curArray=lsMap.get(cybf);
            curArray.add(oo);
        }
        for (Map.Entry<String, JSONArray> entry : lsMap.entrySet()) {
            long docCount = entry.getValue().stream().mapToLong(it -> ((JSONObject) it).getLong("docCount")).sum();
            JSONObject oo=new JSONObject();

            oo.put("ks",entry.getKey());
            oo.put("docCount",docCount);
            oo.put("r",100);

            JSONArray tmpLs=entry.getValue();
            tmpLs.sort(new Comparator<Object>() {
                @Override
                public int compare(Object o1, Object o2) {
                    JSONObject oo1=(JSONObject)o1;
                    JSONObject oo2=(JSONObject)o2;
                    return oo2.getLong("docCount").compareTo(oo1.getLong("docCount"));
                }
            });
            if(entry.getValue().size()>10){
                double r=tmpLs.subList(0,10).stream().
                        mapToLong(it->((JSONObject)it).getLong("docCount")).sum()*100.0/docCount;
                oo.put("r",String.format("%.2f",r).toString());

            }
            tmpLs.forEach(it->{
                JSONObject oo1=(JSONObject)it;
                oo1.put("weightAvg",String.format("%.2f",oo1.getDouble("weightAvg")).toString());
                oo1.put("bedratioAvg",String.format("%.2f",oo1.getDouble("bedratioAvg")).toString());
                oo1.put("costratioAvg",String.format("%.2f",oo1.getDouble("costratioAvg")).toString());
            });
            oo.put("ls",tmpLs.subList(0,Math.min(10,entry.getValue().size())));
            rs.add(oo);

        }
        rs.sort(new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                JSONObject oo1=(JSONObject)o1;
                JSONObject oo2=(JSONObject)o2;
                return oo2.getLong("docCount").compareTo(oo1.getLong("docCount"));
            }
        });



        return rs;
    }

    @Autowired
    CHSDRGMapper chsdrgMapper;

    private ChartSingleSeriesRenderData adrgPipeChar(JSONArray array,String title,Long total){

        List<String>series=new LinkedList<>();
        List<Long>vals=new LinkedList<>();
        Map<String,String> serieMap=new HashMap<String,String>(){
            {
                put("nk","图3 内科病种");
                put("wk","图4 手术种类");
                put("cz","图5 操作种类");
            }
        };
        title=serieMap.get(title);
        long sum=0;
        for (Object o : array) {
            JSONObject oo=(JSONObject)o;
            series.add(oo.getString("adrgName"));
            vals.add(oo.getLong("docCount"));
            sum+=oo.getLong("docCount");
        }
        if(sum<total){
            series.add("其他");
            vals.add(total-sum);
        }
        ChartSingleSeriesRenderData drgPieChart = Charts.ofSingleSeries(title, series.toArray(new String[0]))
                .series("类型", vals.toArray(new Long[0])).create();
        return drgPieChart;

    }

    private ChartSingleSeriesRenderData drgPieChart(JSONArray array,Map<String,Object>params){

        Map<String,Long> map=new HashMap<>();
        //1.内科、外科、操作统计
        List<String>series=new LinkedList<>();
        List<Long>vals=new LinkedList<>();

        Map<String,String>colMap=new HashMap<String,String>(){
            {
                put("nk","内科");
                put("wk","外科");
                put("cz","操作");
            }
        };
        for (Object o : array) {
            JSONObject oo=(JSONObject)o;
            String k=oo.getString("grpinfodrgingrptype");
            k=colMap.get(k);
            Long docCount=oo.getLong("docCount");
           series.add(k);
           vals.add(docCount);
        }
        for (String k:colMap.values()){
            if(!series.contains(k)){
                series.add(k);
                vals.add(0L);
            }
        }
        for (int i = 0; i < series.size(); i++) {
            for (Map.Entry<String, String> entry : colMap.entrySet()) {
                if(series.get(i).equals(entry.getValue())){
                    params.put(entry.getKey(),vals.get(i));
                    break;
                }
            }

        }
        ChartSingleSeriesRenderData drgPieChart = Charts.ofSingleSeries("图2 医院技术结构", series.toArray(new String[0]))
                .series("类型", vals.toArray(new Long[0])).create();
        return drgPieChart;
    }



    /**
     * 生成MDC相关图标信息
     * @param array
     * @return
     */
    private ChartMultiSeriesRenderData mdcChar(JSONArray array){
        List<String> series=new LinkedList<>();
        List<Double> dataList=new LinkedList<>();
        for (Object o : array) {
            JSONObject oo=(JSONObject)o;
            series.add(oo.getString("mdcName"));
            dataList.add(Math.round(oo.getDouble("weightSum")*100)/100.0);
        }
        if(series.size()==0){
            series.add("");
            dataList.add(0d);
        }
        ChartMultiSeriesRenderData chart = Charts.ofMultiSeries("图1 医院服务总量", series.toArray(new String[0]))
                .addSeries("总权重", dataList.toArray(new Double[0]))
                .create();

        return chart;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class KeyPair<T1,T2,T3>{

        public KeyPair(T1 key,T2 val){
            this.key=key;
            this.val=val;
        }
        private T1 key;
        private T2 val;
        private T3 val1;
    }


    public List<KeyPair<String,Double,String>> 未入组原因列表(String time,String stime,String etime){
        BoolQueryBuilder must=new BoolQueryBuilder();
        must.must(QueryBuilders.rangeQuery(time).gte(stime).lte(etime));
        must.must(QueryBuilders.termQuery("ingrp",false));
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                .addAggregation(AggregationBuilders.terms("rzlb").field("grpinfo.rzlb.keyword"))
                .withPageable(PageRequest.of(0, 1))
                .withQuery(must);
        SearchHits<MiniPerformanceInfo> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), MiniPerformanceInfo.class);
        Aggregation rzlb = search.getAggregations().get("rzlb");
        ParsedStringTerms terms=(ParsedStringTerms)rzlb;

        List<KeyPair<String,Double,String>> pairs=new ArrayList<KeyPair<String,Double,String>>();
        for (Terms.Bucket bucket : terms.getBuckets()) {

            KeyPair<String,Double,String> pair=new KeyPair<String,Double,String>(bucket.getKeyAsString(),bucket.getDocCount()*1.0);

            pairs.add(pair);
        }

        return pairs;
    }


    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 数据汇总
     * @param time
     * @param stime
     * @param etime
     * @param grp
     * @param where
     * @param page
     * @param size
     * @return
     */
    public JSONObject innerGrpls( String time,
                                 String stime,
                                 String etime,
                                 String grp,
                                 String where,
                                 String sort,
                                 int page,
                                 int size){
        BoolQueryBuilder must = QueryBuilders.boolQuery();
        must.must(QueryBuilders.rangeQuery(time).gte(stime).lte(etime));

        //生成查询条件
        if(!StringUtils.isEmpty(where)){
            where= EncodingUtil.decodeURIComponent(where);
            List<PfmController.SimpleEsWhere> wheres= JSON.parseArray(where, PfmController.SimpleEsWhere.class);
            for (PfmController.SimpleEsWhere w : wheres) {
                if(w.getOp().equals("eq")){
                    must.must(QueryBuilders.termQuery(w.getCol(),w.getVal()));
                }else if(w.getOp().equals("lk")){
                    must.must(QueryBuilders.matchPhraseQuery(w.getCol(),w.getVal()));
                }else if(w.getOp().equals("in")){
                    String []vals=w.getVal().toString().split(",");
                    must.must(QueryBuilders.termsQuery(w.getCol(),vals));
                }else if(w.getOp().equals("lt")){
                    must.must(QueryBuilders.rangeQuery(w.getCol()).lt(w.getVal()));
                }else if(w.getOp().equals("lte")){
                    must.must(QueryBuilders.rangeQuery(w.getCol()).lte(w.getVal()));
                }else if(w.getOp().equals("gt")){
                    must.must(QueryBuilders.rangeQuery(w.getCol()).gt(w.getVal()));
                }else if(w.getOp().equals("gte")){
                    must.must(QueryBuilders.rangeQuery(w.getCol()).gte(w.getVal()));
                }else if(w.getOp().equals("neq")){
                    must.mustNot(QueryBuilders.termQuery(w.getCol(),w.getVal()));
                }
            }
        }

        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();
        for (String g : grp.split(",")) {
            String k=g.replaceAll("\\.","");
            TermsValuesSourceBuilder b = new TermsValuesSourceBuilder(k).field(g + ".keyword").missingBucket(true);
            sources.add(b);
        }

        CompositeAggregationBuilder composite = AggregationBuilders.composite("grp", sources);
        composite.size(10000);

        //------->统计指标  开始<--------
        List<AggregationBuilder> builders = new ArrayList<AggregationBuilder>();
        Map<String,String> metrics=new HashMap<String,String>(){
            {
                //MDC数量
                put("mdcCount","grpinfo.mdc.keyword");
                //put("ingrpCount","grpinfo.mdc.keyword");
                //住院费用
                put("zfySum","zfy");
                //住院平均费用
                put("zfyAvg","zfy");
                //平均权重(CMI)
                put("weightAvg","grpinfo.weight");
                //总权重
                put("weightSum","grpinfo.weight");
                //费用消耗
                put("costratioAvg","grpinfo.costratio");
                //时间消耗
                put("bedratioAvg","grpinfo.bedratio");
                //ADRG数量
                put("adrgCount","grpinfo.adrg.keyword");
                //DRG数量
                put("drgCount","grpinfo.drg.keyword");
                //标准总费用
                put("benchmarkFeeSum","grpinfo.benchmarkFee");
                //标准平均费用
                put("benchmarkFeeAvg","grpinfo.benchmarkFee");
            }
        };
        for (Map.Entry<String, String> entry : metrics.entrySet()) {
            if(entry.getKey().contains("Count")){
                builders.add(AggregationBuilders.cardinality(entry.getKey()).field(entry.getValue()));
            }
            if(entry.getKey().contains("Sum")){
                builders.add(AggregationBuilders.sum(entry.getKey()).field(entry.getValue()));
            }
            if(entry.getKey().contains("Avg")){
                builders.add(AggregationBuilders.avg(entry.getKey()).field(entry.getValue()));
            }
        }
        //入组数
        builders.add(AggregationBuilders.filter("ingrpCount",QueryBuilders.termQuery("ingrp",true)));
        //死亡人数
        builders.add(AggregationBuilders.filter("deadCount",QueryBuilders.termQuery("lyfs.keyword","5")));
        //人次
        builders.add(AggregationBuilders.count("pCount").field("bah.keyword"));

        //------->统计指标  结束<--------
        for (AggregationBuilder build : builders) {
            composite.subAggregation(build);
        }
        List<FieldSortBuilder> sorts = null;
        if (!StringUtils.isEmpty(sort)) {
            sorts = new ArrayList<FieldSortBuilder>();
            for (String s : sort.split(",")) {
                String col=s.split("-")[0];
                String order=s.split("-")[1];
                FieldSortBuilder forder = SortBuilders.fieldSort(col);
                if (order.equals("asc")) {
                    forder.order(SortOrder.ASC);
                } else {
                    forder.order(SortOrder.DESC);
                }
                sorts.add(forder);
            }

            // System.out.println("size:"+size);

        }
        BucketSortPipelineAggregationBuilder bucketOrder = PipelineAggregatorBuilders
                .bucketSort("my_bucket_sort", sorts).from((page)*size).size(size);
        composite.subAggregation(bucketOrder);

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                .addAggregation(composite)
                .withPageable(PageRequest.of(page, 1))
                .withQuery(must);

        for (AggregationBuilder build : builders) {
            nativeSearchQueryBuilder.build().addAggregation((AbstractAggregationBuilder<?>) build);
        }
        SearchHits<MiniPerformanceInfo> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), MiniPerformanceInfo.class);
        ParsedComposite parsedComposite =(ParsedComposite) search.getAggregations().get(composite.getName());
        List<ParsedComposite.ParsedBucket> buckets = parsedComposite.getBuckets();

        ActionTwo<Aggregation,JSONObject> actionTwo=(subAgg,o)->{
            if(subAgg instanceof ParsedValueCount){
                ParsedValueCount valueCount = (ParsedValueCount) subAgg;
                o.put(valueCount.getName(),valueCount.value());
            }else if(subAgg instanceof ParsedFilter){
                ParsedFilter filter=(ParsedFilter)subAgg;
                o.put(filter.getName(),filter.getDocCount());
            }else if(subAgg instanceof ParsedAvg) {
                ParsedAvg avg=(ParsedAvg)subAgg;
                o.put(avg.getName(),avg.value());
            }else if(subAgg instanceof ParsedSum){
                ParsedSum sum=(ParsedSum)subAgg;
                o.put(sum.getName(),sum.value());
            }else if(subAgg instanceof ParsedCardinality) {
                ParsedCardinality cardinality=(ParsedCardinality)subAgg;
                o.put(cardinality.getName(),cardinality.value());
            }
        };

        JSONArray array=new JSONArray();
        for (ParsedComposite.ParsedBucket bucket : buckets) {
            JSONObject o=new JSONObject();
            for (Map.Entry<String, Object> entry : bucket.getKey().entrySet()) {
                o.put(entry.getKey(),entry.getValue());
            }
            o.put("docCount",bucket.getDocCount());
            for (Aggregation subAgg : bucket.getAggregations()) {
                actionTwo.accept(subAgg,o);

            }
            array.add(o);

        }
        JSONObject totalObj=new JSONObject();
        for (Aggregation aggregation : search.getAggregations()) {
            if(aggregation.getName().equals(composite.getName())){
                continue;
            }
            actionTwo.accept(aggregation,totalObj);
        }

        JSONObject o=new JSONObject();
        o.put("ls",array);
        o.put("total",totalObj);
        return o;
    }



}
